/*
 * 本案例功能
 * 接入个人服务器，发布信息，订阅信息，
 * 实现温度模块 光敏模块数据上传 用手机app和个人物联网平台实现红外遥控器功能 可通过天猫精灵开关电视
 * D4 温度上传端口
 * A0 光照数据
 * D2 红外发射模块口
 * 上传主题 getMessage
 * 订阅主题 tv_control
 */
#define BLINKER_WIFI
#define BLINKER_ALIGENIE_OUTLET
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRutils.h>
#define BLINKER_PRINT Serial
#include <Blinker.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <OneWire.h>
#include <DS18B20.h>
#define BUS D4//温度读取端口
#include<DallasTemperature.h>
#define PRODUCT_ID    "TOP" //产品名（）
#define API_KEY    "tx6WM==zmW21Z2pt4susBRlHMuY="//产品密钥
#define DEVICE_ID "tv_device"//设备名
#define TOPIC     "tv_control"//订阅主题
//电视遥控器对应信号 （本例所用品牌为康佳）
uint16_t left[75] = {2976, 2962,  512, 1470,  512, 1474,  514, 1474,  536, 1448,  514, 1474,  538, 1446,  514, 2470,  538, 1448,  512, 1474,  512, 1474,  514, 2466,  538, 1452,  510, 2470,  540, 2444,  514, 1474,  538, 2446,  512, 3934,  514, 22016,  2980, 2958,  540, 1470,  516, 1468,  518, 1468,  520, 1466,  518, 1468,  516, 1470,  492, 2466,  544, 1466,  520, 1466,  522, 1464,  522, 2438,  544, 1466,  522, 2436,  550, 2460,  550, 1436,  548, 2410,  578, 3872,  584};  // UNKNOWN 9A6A367F

uint16_t right[75] = {2972, 2964,  510, 1476,  508, 1476,  510, 1476,  510, 1476,  508, 1478,  510, 1478,  506, 2478,  508, 1476,  508, 1476,  510, 1478,  508, 2474,  512, 1478,  508, 2476,  506, 2476,  508, 2476,  508, 1478,  508, 3942,  506, 22026,  2968, 2970,  508, 1476,  508, 1480,  508, 1478,  508, 1478,  510, 1476,  510, 1476,  510, 2476,  508, 1478,  508, 1478,  508, 1478,  510, 2474,  508, 1478,  510, 2474,  508, 2476,  506, 2478,  508, 1480,  506, 3942,  508};  // UNKNOWN 8AA60F6B

uint16_t up[75] = {2968, 2966,  508, 1476,  510, 1476,  508, 1478,  508, 1480,  506, 1480,  508, 1476,  512, 2472,  508, 1480,  506, 1478,  510, 1478,  508, 2474,  510, 1478,  508, 2474,  510, 1476,  510, 2474,  506, 2478,  510, 3940,  508, 22022,  2970, 2966,  506, 1480,  506, 1478,  506, 1482,  504, 1480,  506, 1480,  508, 1480,  506, 2478,  508, 1480,  506, 1478,  508, 1478,  508, 2476,  508, 1478,  508, 2478,  508, 1478,  506, 2478,  506, 2478,  506, 3940,  506};  // UNKNOWN 2A84BE27

uint16_t down[75] = {3046, 2888,  522, 1466,  544, 1442,  546, 1464,  520, 1440,  548, 1438,  546, 1440,  518, 2464,  548, 1438,  546, 1442,  546, 1440,  546, 2434,  548, 1442,  548, 2432,  552, 2432,  554, 1432,  548, 1440,  550, 3898,  550, 22982,  3010, 2926,  546, 1440,  546, 1440,  546, 1440,  546, 1440,  546, 1440,  544, 1442,  546, 2438,  544, 1442,  548, 1438,  548, 1438,  546, 2436,  544, 1442,  546, 2438,  544, 2438,  542, 1444,  546, 1442,  544, 3906,  540};  // UNKNOWN A7DF77E3

uint16_t power[75] = {2970, 2964,  510, 1478,  480, 1506,  506, 1478,  506, 1480,  504, 1482,  480, 1506,  506, 2478,  504, 1480,  506, 1480,  506, 1480,  506, 1480,  506, 1480,  506, 2476,  482, 1506,  508, 2476,  482, 2504,  504, 3942,  508, 23024,  2970, 2968,  506, 1480,  506, 1480,  504, 1480,  504, 1482,  506, 1480,  504, 1484,  504, 2478,  506, 1480,  506, 1480,  506, 1480,  506, 1482,  506, 1480,  506, 2478,  508, 1478,  508, 2476,  506, 2478,  506, 3944,  480};  // UNKNOWN B1477CA3

uint16_t back[75] = {2972, 2966,  508, 1476,  510, 1476,  510, 1478,  508, 1478,  508, 1478,  508, 1478,  508, 2476,  506, 1480,  508, 1478,  508, 1478,  508, 2472,  510, 2476,  506, 1480,  510, 1476,  508, 1480,  508, 1478,  490, 3960,  506, 24028,  2970, 2966,  482, 1502,  508, 1478,  508, 1476,  510, 1478,  504, 1480,  506, 1482,  506, 2478,  508, 1478,  508, 1478,  508, 1482,  504, 2476,  508, 2476,  508, 1478,  508, 1480,  506, 1478,  482, 1504,  510, 3942,  506};  // UNKNOWN 8EDA347

uint16_t ok[75] = {2972, 2964,  536, 1448,  512, 1476,  512, 1474,  508, 1476,  518, 1470,  514, 1472,  516, 2470,  510, 1476,  540, 1446,  538, 1448,  512, 2472,  512, 1474,  510, 2474,  538, 2446,  510, 2472,  510, 2478,  510, 3936,  512, 21020,  2970, 2966,  510, 1474,  508, 1478,  506, 1478,  508, 1478,  508, 1478,  508, 1476,  508, 2476,  506, 1482,  508, 1478,  506, 1480,  506, 2476,  508, 1478,  508, 2476,  506, 2476,  506, 2478,  508, 2476,  508, 3940,  508};  // UNKNOWN F42D6A63

uint16_t homes[75] = {2976, 2960,  538, 1444,  514, 1472,  510, 1474,  510, 1476,  512, 1474,  528, 1458,  514, 2470,  538, 1446,  538, 1450,  512, 1472,  540, 2444,  514, 2468,  512, 2474,  538, 1446,  512, 1472,  512, 1474,  514, 3936,  538, 22990,  2998, 2940,  512, 1474,  512, 1474,  536, 1450,  510, 1474,  508, 1476,  510, 1476,  512, 2472,  512, 1474,  512, 1474,  512, 1472,  512, 2472,  510, 2474,  510, 2474,  510, 1474,  512, 1474,  510, 1478,  508, 3938,  510};  // UNKNOWN 82C82B4F

uint16_t sound_up[75] = {2976, 2960,  514, 1472,  516, 1470,  514, 1474,  512, 1474,  512, 1474,  536, 1448,  538, 2444,  514, 1472,  512, 1474,  510, 1476,  512, 1476,  512, 2474,  512, 1474,  514, 1474,  512, 2472,  538, 2446,  512, 3936,  512, 23020,  2974, 2964,  508, 1476,  508, 1478,  508, 1480,  510, 1474,  510, 1474,  512, 1474,  510, 2476,  510, 1476,  508, 1476,  512, 1476,  510, 1476,  508, 2476,  510, 1478,  508, 1478,  508, 2476,  508, 2478,  506, 3942,  510};  // UNKNOWN 21540FC3

uint16_t sound_down[75] = {3040, 2898,  548, 1436,  548, 1438,  552, 1434,  550, 1436,  550, 1434,  550, 1436,  550, 2434,  550, 1436,  548, 1438,  548, 1438,  548, 1438,  550, 2432,  550, 1438,  548, 1438,  550, 2436,  548, 1436,  550, 3900,  546, 23986,  3004, 2932,  542, 1444,  540, 1446,  544, 1444,  542, 1444,  538, 1448,  542, 1444,  540, 2444,  542, 1442,  518, 1468,  542, 1444,  542, 1444,  542, 2442,  518, 1470,  542, 1444,  542, 2442,  542, 1446,  542, 3908,  514};  // UNKNOWN 31A9CF7B

IRsend irsend(4);

char auth[] = "0c39eb647f6d";//天猫精灵接入blinker的设备key
char ssid[] = "Fishing WiFi ";
char pswd[] = "zheshiyigewifi";
double tempertureRead;
WiFiClient wifiClient;
OneWire onewire(BUS);
DallasTemperature sensors(&onewire);
Ticker ticker;
int count = 0; //ticker1控制 数据上传下发的间隔时间（s）
PubSubClient mqttClient(wifiClient);
const char* mqttServer = "******";//服务器地址
const uint16_t mqttPort = 1883;//mqtt接口端口
char msgJson[75];//存json下发信息数据
char msg_buf[200];//存json上传数据及标识位
double brightNum;
bool oState = false;
void aligeniePowerState(const String & state)
{
  BLINKER_LOG("need set power state: ", state);

  if (state == BLINKER_CMD_ON) {
    digitalWrite(LED_BUILTIN, LOW);
    irsend.sendRaw(power, 75, 38); 
    BlinkerAliGenie.powerState("on");
    BlinkerAliGenie.print();
    oState = true;
  }
  else if (state == BLINKER_CMD_OFF) {
    digitalWrite(LED_BUILTIN, HIGH);
    irsend.sendRaw(power, 75, 38); 
    BlinkerAliGenie.powerState("off");
    BlinkerAliGenie.print();
    oState = false;
  }
}
void aligenieQuery(int32_t queryCode)
{
  BLINKER_LOG("AliGenie Query codes: ", queryCode);

  switch (queryCode)
  {
    case BLINKER_CMD_QUERY_ALL_NUMBER :
      BLINKER_LOG("AliGenie Query All");
      BlinkerAliGenie.powerState(oState ? "on" : "off");
      BlinkerAliGenie.print();
      break;
    case BLINKER_CMD_QUERY_POWERSTATE_NUMBER :
      BLINKER_LOG("AliGenie Query Power State");
      BlinkerAliGenie.powerState(oState ? "on" : "off");
      BlinkerAliGenie.print();
      break;
    default :
      BlinkerAliGenie.powerState(oState ? "on" : "off");
      BlinkerAliGenie.print();
      break;
  }
}

// 如果未绑定的组件被触发，则会执行其中内容
void dataRead(const String & data)
{
  BLINKER_LOG("Blinker readString: ", data);
}
void setup() {
  // 初始化串口
  Serial.begin(9600);
#if defined(BLINKER_PRINT)
  BLINKER_DEBUG.stream(BLINKER_PRINT);
#endif
  irsend.begin();
  pinMode(A0, INPUT);
  WiFi.mode(WIFI_STA);
  mqttClient.setServer(mqttServer, mqttPort);
  // 设置MQTT订阅回调函数
  mqttClient.setCallback(receiveCallback);
  connectMQTTServer();
  ticker.attach(1, addCount);
  sensors.begin();
  // 初始化blinker
  Blinker.begin(auth, ssid, pswd);
  Blinker.attachData(dataRead);
  BlinkerAliGenie.attachPowerState(aligeniePowerState);
  BlinkerAliGenie.attachQuery(aligenieQuery);
}

void loop() {
  Blinker.run();
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    // 每隔2秒钟发布一次信息
    // 保持心跳 若电机正在运转，暂时不发信息（由于mcu没有多线程，不能同时运转电机和上传下发数据）
    if (count >= 2)
    {
        sensors.requestTemperatures();
        tempertureRead=sensors.getTempCByIndex(0);
        pubMsgAndroid();
        //pubMQTTmsg();
        
        count = 0;
      }
      mqttClient.loop();
  } else {                  // 如果开发板未能成功连接服务器
    connectMQTTServer();    // 则尝试连接服务器
  }
}
//连接mqtt服务器
void connectMQTTServer() {
  String clientId = DEVICE_ID;
  String productId = PRODUCT_ID;
  String apiKey = API_KEY;
  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str(), productId.c_str(), apiKey.c_str())) {
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address: ");
    Serial.println(mqttServer);
    Serial.println("ClientId:");
    Serial.println(clientId);
    subscribeTopic(); // 订阅指定主题
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(1000);
  }
}
// 订阅指定主题
void subscribeTopic() {
  // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时，所订阅的主题名称不同
  String topicString = TOPIC;
  char subTopic[topicString.length() + 1];
  strcpy(subTopic, topicString.c_str());

  // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
  if (mqttClient.subscribe(subTopic)) {
    Serial.println("Subscrib Topic:");
    Serial.println(subTopic);
  } else {
    Serial.print("Subscribe Fail...");
  }
}
//获取下发指令topic 指定主题 payload 下发信息，以字节存储 length 下发信息长度
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  String receiveMessage;
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    receiveMessage += (char)payload[i];
  }
  Serial.println("----" + receiveMessage + "----");
  Serial.print("Message Length(Bytes) ");
  Serial.println(length);
  ///
  StaticJsonDocument<256> doc;
  deserializeJson(doc, receiveMessage);

  int up1 = doc["up"]; // 1
  int down1 = doc["down"]; // 1
  int left1 = doc["left"]; // 1
  int right1 = doc["right"]; // 1
  int ok1 = doc["ok"]; // 1
  int power1 = doc["power"]; // 1
  int back1 = doc["back"]; // 1
  int sound_up1 = doc["sound_up"]; // 1
  int sound_down1 = doc["sound_down"]; // 1
  int homes1 = doc["home"]; // 1
  receiveMessage = "";
  if (up1==1)
  {
    irsend.sendRaw(up, 75, 38); 
  } else if (down1==1) {
     irsend.sendRaw(down, 75, 38); 
  } else if (left1==1) {
     irsend.sendRaw(left, 75, 38); 
  } else if (right1==1) {
     irsend.sendRaw(right, 75, 38); 
  } else if (ok1==1) {
     irsend.sendRaw(ok, 75, 38); 
  } else if (homes1==1) {
     irsend.sendRaw(homes, 75, 38); 
  } else if (back1==1) {
     irsend.sendRaw(back, 75, 38); 
  } else if (power1==1) {
     irsend.sendRaw(power, 75, 38); 
  } else if (sound_up1==1) {
     irsend.sendRaw(sound_up, 75, 38); 
  } else if (sound_down1==1) {
     irsend.sendRaw(sound_down, 75, 38); 
  }
 
}
//对指定主题上传信息
void pubMsgAndroid() {
  String topicString = "getMessage";
  char publishTopic[topicString.length() + 1];
  strcpy(publishTopic, topicString.c_str());
  //json数据转换为数组
  DynamicJsonDocument doc(64);
  doc["temperature"] = tempertureRead;
  brightNum=analogRead(A0);
 
  doc["bright"] = (int)((100-brightNum/1024*100)*100+0.5)/100.0;
  doc["doorLock"] = digitalRead(D8);
  serializeJson(doc, Serial);
  String jsonCode;
  serializeJson(doc, jsonCode);
  Serial.print("json Code: "); Serial.println(jsonCode);
  String messageString = jsonCode;
  char publishMsg[messageString.length() + 1];
  strcpy(publishMsg, messageString.c_str());
  int json_len = strlen(publishMsg);
  mqttClient.publish(publishTopic, publishMsg, json_len);
}
void addCount() {
  count++;
}
